<template>
  <Dialog
    v-model="dialogVisible"
    :close-on-press-escape="dialogCloseOnEsc"
    @open="handleDialogOpen"
    @opened="handleDialogOpened"
    @close="handleDialogClose"
    title="测试发送"
    width="1000"
  >
    <el-form
      ref="formRef"
      v-loading="formLoading"
      :model="formData"
      :rules="formRules"
      :validate-on-rule-change="false"
      label-width="140px"
    >
      <el-form-item label="模板类型" prop="type">
        <span>{{ getDictLabel(DICT_TYPE.system_mail_template_type, formData.type) }}</span>
      </el-form-item>
      <el-form-item label="模板标题" prop="title">
        <el-input v-model="formData.title" readonly />
      </el-form-item>
      <el-form-item
        v-if="formData.type === SystemMailTemplateTypeEnum.Placeholder"
        label="模板内容"
        prop="content"
      >
        <Editor
          ref="placeholderEditorRef"
          :model-value="formData.content"
          @fullscreen="handleWangEditorFullscreen"
          height="160px"
          disabled
        />
      </el-form-item>
      <el-form-item
        v-if="formData.type === SystemMailTemplateTypeEnum.Freemarker"
        prop="content"
        class="editor-container"
        :class="{ fullscreen: isAceEditor1Fullscreen }"
      >
        <template #label>
          <div @dblclick="toggleAceEditorFullscreen(1)">
            <Tooltip message="双击标签：全屏切换" title="模板内容" />
          </div>
        </template>
        <v-ace-editor
          v-model:value="formData.content"
          lang="ftl"
          theme="chrome"
          readonly
          :options="{ fontSize: 13, showPrintMargin: false }"
          style="width: 100%; height: 100%"
        />
      </el-form-item>
      <el-form-item label="收件邮箱" prop="mail">
        <el-input v-model="formData.mail" placeholder="请输入收件邮箱" />
      </el-form-item>
      <template v-if="formData.type === SystemMailTemplateTypeEnum.Placeholder">
        <el-form-item
          v-for="param in formData.params"
          :key="param"
          :label="`参数 {${param}}`"
          :prop="'templateParams.' + param"
        >
          <el-input v-model="formData.templateParams[param]" :placeholder="`请输入${param}参数`" />
        </el-form-item>
      </template>
      <el-form-item
        v-if="formData.type === SystemMailTemplateTypeEnum.Freemarker && formData.params?.length"
        prop="templateParamsJson"
        class="editor-container"
        :class="{ fullscreen: isAceEditor2Fullscreen }"
      >
        <template #label>
          <div @dblclick="toggleAceEditorFullscreen(2)">
            <Tooltip message="双击标签：全屏切换，Ctrl-Shift-F：内容格式化" title="模板参数" />
          </div>
        </template>
        <v-ace-editor
          ref="paramsAceEditorRef"
          v-model:value="formData.templateParamsJson"
          lang="json"
          theme="chrome"
          :options="{
            fontSize: 13,
            useWorker: true,
            tabSize: 2,
            useSoftTabs: true,
            showPrintMargin: false
          }"
          style="width: 100%; height: 100%"
        />
      </el-form-item>
    </el-form>
    <template #footer>
      <el-button :disabled="formLoading" type="primary" @click="submitForm">确 定</el-button>
      <el-button @click="dialogVisible = false">取 消</el-button>
    </template>
  </Dialog>
</template>

<script setup lang="ts">
import { MailTemplateApi, MailTemplateSendVO } from '@/api/system/mail/mail_template'
import type { FormRules } from 'element-plus'
import { DICT_TYPE, getDictLabel } from '@/utils/dict'
import { SystemMailTemplateTypeEnum } from '@/utils/constants'
import { VAceEditor } from 'vue3-ace-editor'
import ace from 'ace-builds'
import 'ace-builds/src-noconflict/mode-ftl'
import 'ace-builds/src-noconflict/mode-json'
import 'ace-builds/src-noconflict/theme-chrome'
import workerJsonUrl from 'ace-builds/src-noconflict/worker-json?url'
import { Editor } from '@/components/Editor'
import { isBlankString, isValidJson } from '@/utils/lizard'

ace.config.setModuleUrl('ace/mode/json_worker', workerJsonUrl)

defineOptions({ name: 'SystemMailTemplateSendForm' })

const message = useMessage() // 消息弹窗

const dialogVisible = ref(false) // 弹窗的是否展示
const dialogCloseOnEsc = ref(true)
const formLoading = ref(false) // 表单的加载中：1）修改时的数据加载；2）提交的按钮禁用

const formDataObj = {
  type: undefined,
  title: undefined,
  content: '',
  params: [],
  mail: undefined,
  templateCode: undefined,
  templateParams: new Map(),
  templateParamsJson: ''
}
// 发送短信表单相关
const formData = ref({ ...formDataObj })
const formRules = reactive<FormRules>({
  mail: [
    { required: true, message: '邮箱不能为空', trigger: 'blur' },
    { type: 'email', message: '请输入正确的邮箱地址', trigger: ['blur', 'change'] }
  ],
  templateCode: [{ required: true, message: '模版编码不能为空', trigger: 'blur' }],
  templateParams: {}
})
const formRef = ref() // 表单 Ref

const open = async (id: number) => {
  dialogVisible.value = true
  resetForm()
  formLoading.value = true
  try {
    const data = await MailTemplateApi.getMailTemplate(id)
    formData.value.type = data.type
    formData.value.title = data.title
    formData.value.content = data.content
    formData.value.params = data.params
    formData.value.templateCode = data.code
    if (data.type === SystemMailTemplateTypeEnum.Placeholder) {
      // 动态构造模版参数对象
      formData.value.templateParams = data.params.reduce((acc, item) => {
        acc[item] = ''
        return acc
      }, {})
      // 动态构造模版参数规则对象，动态变更规则会导致表单规则被提前执行，需要重置校验结果，否则弹窗一打开就已经有表单校验结果提示信息了
      formRules.templateParams = data.params.reduce((acc, item) => {
        acc[item] = [{ required: true, message: `参数${item}不能为空`, trigger: 'blur' }]
        return acc
      }, {})
    } else {
      if (data.params?.length) {
        formData.value.templateParamsJson = JSON.stringify(
          data.params.reduce((acc, item) => {
            acc[item] = null
            return acc
          }, {}),
          null,
          2
        )
        formRules.templateParamsJson = [
          {
            required: true,
            message: `模板参数不能为空`,
            trigger: 'blur'
          },
          {
            validator: (_rule, value, callback) => {
              if (!isValidJson(value)) {
                callback(new Error('模板参数为非法的json格式'))
              } else {
                callback()
              }
            },
            trigger: 'blur'
          }
        ]
      }
    }
  } finally {
    formLoading.value = false
  }
}
defineExpose({ open }) // 提供 open 方法，用于打开弹窗

const submitForm = async () => {
  if (await formValidate(formRef)) return
  formLoading.value = true
  try {
    const data = {
      mail: formData.value.mail,
      templateCode: formData.value.templateCode
    } as unknown as MailTemplateSendVO
    if (formData.value.type === SystemMailTemplateTypeEnum.Placeholder) {
      data.templateParams = formData.value.templateParams
    } else if (formData.value.params?.length) {
      data.templateParams = JSON.parse(formData.value.templateParamsJson)
    }
    const logId = await MailTemplateApi.sendMailTemplate(data)
    if (logId) {
      message.success('发送请求提交成功，发送日志编号：' + logId)
    }
    dialogVisible.value = false
  } finally {
    formLoading.value = false
  }
}

const resetForm = () => {
  formData.value = { ...formDataObj }
  formRef.value?.resetFields()
  isAceEditor1Fullscreen.value = false
  isAceEditor2Fullscreen.value = false
  isWangEditorFullscreen.value = false
}

const placeholderEditorRef = ref<InstanceType<typeof Editor>>()
const isWangEditorFullscreen = ref(false)
const handleWangEditorFullscreen = (fullscreen: boolean) => {
  isWangEditorFullscreen.value = fullscreen
  dialogCloseOnEsc.value = !isWangEditorFullscreen.value
}

const paramsAceEditorRef = ref()
const isAceEditor1Fullscreen = ref(false)
const isAceEditor2Fullscreen = ref(false)
const toggleAceEditorFullscreen = (editorNo: number) => {
  if (editorNo === 1) {
    isAceEditor1Fullscreen.value = !isAceEditor1Fullscreen.value
    dialogCloseOnEsc.value = !isAceEditor1Fullscreen.value
  } else if (editorNo === 2) {
    isAceEditor2Fullscreen.value = !isAceEditor2Fullscreen.value
    dialogCloseOnEsc.value = !isAceEditor2Fullscreen.value
  }
}

const handleEscKey = async (event) => {
  if (event.key === 'Escape') {
    if (isAceEditor1Fullscreen.value) {
      toggleAceEditorFullscreen(1)
      event.stopPropagation()
    } else if (isAceEditor2Fullscreen.value) {
      toggleAceEditorFullscreen(2)
      event.stopPropagation()
    } else if (isWangEditorFullscreen.value) {
      // 如果 wangeditor 处于全屏模式，则退出全屏
      ;(await placeholderEditorRef.value?.getEditorRef())?.unFullScreen()
      event.stopPropagation()
    }
  }
}

const handleDialogOpen = () => {
  document.addEventListener('keydown', handleEscKey)
}

const handleDialogOpened = () => {
  nextTick(() => {
    const aceEditor: ace.Editor = paramsAceEditorRef.value?.getAceInstance()
    if (aceEditor) {
      aceEditor.commands.addCommand({
        name: 'customFormatJson',
        bindKey: { win: 'Ctrl-Shift-F', mac: 'Ctrl-Shift-F' },
        exec: (editor) => {
          const editorValue = editor.getValue()
          try {
            if (!isBlankString(editorValue)) {
              editor.setValue(JSON.stringify(JSON.parse(editorValue), null, 2))
              editor.clearSelection()
            }
          } catch (err) {
            console.log('非法的json内容')
          }
        }
      })
    }
  })
}

const handleDialogClose = () => {
  document.removeEventListener('keydown', handleEscKey)
}
</script>

<style scoped lang="scss">
.editor-container {
  height: 160px;
}

/* 全屏模式 */
.editor-container.fullscreen {
  position: fixed !important;
  top: 0 !important;
  left: 0 !important;
  z-index: 1000 !important;
  width: 100vw !important;
  height: 100vh !important;
  max-width: none !important;
  max-height: none !important;
  background: white !important;
}
</style>
